package com.acctrue.common.jwt.filter;
import com.acctrue.common.core.domain.R;
import com.acctrue.common.core.domain.UserToken;
import com.acctrue.common.core.enums.ResultTypeEnum;
import com.acctrue.common.jwt.utils.JwtTokenUtil;
import com.acctrue.common.core.domain.UserTokenInfo;
import com.alibaba.fastjson2.JSON;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;

/**
 * @author: jsc
 * @createTime: 2023-11-22 19:03
 * @version: 1.0.0
 * @Description: Jwt 拦截器
 */
@Slf4j
@Component
public class JwtFilter extends HandlerInterceptorAdapter {

    @Resource
    JwtTokenUtil jwtTokenUtil;

    @Value("${jwt.expire.accessToken}")
    public Integer accessTokenExpire;

    @Value("${jwt.expire.refreshToken}")
    public Integer refreshTokenExpire;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {

        String refreshToken = request.getHeader(jwtTokenUtil.refreshToken);

        String accessToken = request.getHeader(jwtTokenUtil.accessToken);

        if (StringUtils.isEmpty(refreshToken)||StringUtils.isEmpty(accessToken)) {
            sendErrorResponse(response, ResultTypeEnum.TOKEN_IS_NULL);
            return false;
        }


        if (jwtTokenUtil.checkBlacklist(refreshToken)||jwtTokenUtil.checkBlacklist(accessToken)) {
            sendErrorResponse(response, ResultTypeEnum.TOKEN_BLACKLIST);
            return false;
        }

        if (jwtTokenUtil.isTokenExpired(refreshToken)) {
            UserTokenInfo userInfoToken = jwtTokenUtil.getUserInfoToken(accessToken);
            // 刷新令牌 放入黑名单
            jwtTokenUtil.addBlacklist(refreshToken, jwtTokenUtil.getExpirationDate(refreshToken));
            // 访问令牌 放入黑名单
            String odlAccessToken = jwtTokenUtil.getAccessTokenByRefresh(refreshToken);
            if (!StringUtils.isEmpty(odlAccessToken)) {
                jwtTokenUtil.addBlacklist(odlAccessToken, jwtTokenUtil.getExpirationDate(odlAccessToken));
            }
            jwtTokenUtil.createToekns(userInfoToken);
            sendExpiredResponse(response, ResultTypeEnum.TOKEN_INVALID,userInfoToken);
            return false;
        }

        if (jwtTokenUtil.isTokenExpired(accessToken)) {
            UserTokenInfo userInfoToken = jwtTokenUtil.getUserInfoToken(accessToken);
            Date nowDate = new Date();
            Date accessTokenExpireDate = new Date(nowDate.getTime() + accessTokenExpire * 1000);
            Date refreshTokenExpireDate = new Date(nowDate.getTime() + refreshTokenExpire * 1000);
            // 创建一个新的accessToken
            String token = jwtTokenUtil.createToken(userInfoToken, nowDate, accessTokenExpireDate);
            UserToken userToken = new UserToken();
            BeanUtils.copyProperties(userInfoToken, userToken);
            userToken.setAccessToken(token);
            userToken.setRefreshToken(refreshToken);
            // 创建 刷新令牌 与 访问令牌 关联关系
            jwtTokenUtil.tokenAssociation(userToken, refreshTokenExpireDate);
            // 老的访问令牌 放入黑名单
            jwtTokenUtil.addBlacklist(accessToken, jwtTokenUtil.getExpirationDate(accessToken));
            sendResponse(response,userInfoToken);
            return false;
        }
        return true;
    }
    private void sendErrorResponse(HttpServletResponse response, ResultTypeEnum resultTypeEnum){
        try{
            response.setStatus(resultTypeEnum.getCode());
            response.setContentType("application/json");
            response.setCharacterEncoding("UTF-8");
            R<String> ok = R.ok(resultTypeEnum.getMsg());
            response.getWriter().write(JSON.toJSONString(ok));
        }catch (Exception e){
            log.error(e.getMessage());
        }
    }
    private void sendExpiredResponse(HttpServletResponse response, ResultTypeEnum resultTypeEnum,UserTokenInfo userInfoToken){
        try{
            response.setStatus(resultTypeEnum.getCode());
            response.setContentType("application/json");
            response.setCharacterEncoding("UTF-8");
            R<UserTokenInfo> ok = R.ok(userInfoToken);
            response.getWriter().write(JSON.toJSONString(ok));
        }catch (Exception e){
            log.error(e.getMessage());
        }
    }
    private void sendResponse(HttpServletResponse response, UserTokenInfo userInfoToken){
        try{
            response.setStatus(500);
            response.setContentType("application/json");
            response.setCharacterEncoding("UTF-8");
            R<UserTokenInfo> ok = R.ok(userInfoToken);
            response.getWriter().write(JSON.toJSONString(ok));
        }catch (Exception e){
            log.error(e.getMessage());
        }
    }
}
